Effective Kotlin : Item 5: Specify your expectations on arguments and state
昨天說的 @Nullable 是契約式設計(Design By Contract)的一環,除了可空性外外,函式或介面參數的合法性是更需要被定義及申明的,這樣被呼叫時開發者可以明確的知道副作用。因此 Kotlin 作為一個現代化程式語言有自帶契約式設計的支持,可以用 require / check / assert 明訂契約
當對於參數的範圍,狀態有期望時,應盡早宣告它們。在 Kotlin 中,主要使用以下方法進行此操作:
以下為 stack pop 的範例
// Part of Stack<T>
fun pop(num: Int = 1): List<T> {
require(num <= size) {
"Cannot remove more elements than current size"
}
check(isOpen) { "Cannot pop from closed stack" }
val ret = collection.take(num)
collection = collection.drop(num)
assert(ret.size == num)
return ret
}
當條件不符時,require/check 會拋出不同的 exception。由 exception 的名稱也可以看出 require 是要檢查傳入的參數狀態, check 是檢查內部或處理後的狀態。
為了使 assert 起作用,需要在 JVM 中啟用斷言功能(-ea)。如果不啟用,assert 將不會進行任何操作
延伸的還有 checkNotNull, requireNotNull
檢查給定的值是否為 null,如果是 null,則拋出 IllegalArgumentException。
val nonNullValue = requireNotNull(possibleNullValue) { "Value must not be null" }
檢查給定的值是否為 null,如果是 null,則拋出 IllegalStateException。
val nonNullValue = checkNotNull(possibleNullValue) { "Value must not be null" }
除了作用相似外。在通過 checkNotNull, requireNotNull 的參數 Kotlin 就會自動視為非空。如下的 validateEmail 本來不能傳入 email:String?
但因為上面通過了requireNotNull(person.email)
,所以 Kotlin 知道那不是空的。就可以直接使用
class Person(val email: String?)
fun validateEmail(email: String) { /*...*/
}
fun sendEmail(person: Person, text: String) {
val email = requireNotNull(person.email)
validateEmail(email)
//...
}
fun sendEmail(person: Person, text: String) {
requireNotNull(person.email)
validateEmail(person.email)
//...
}
check 函數的工作方式與 require 類似,但當所述的期望未被滿足時,它會拋出 IllegalStateException。它檢查某個狀態是否正確,通常在 require 區塊之後。但是,有些狀態期望是局部的,check 可以稍後使用。
TOMBOY